#include "ThreadPool.h"
#include <iostream>

ThreadPool::ThreadPool(int min, int max) : m_max_thread(max), m_exit_thread(0),
m_min_thread(min), m_shop(false), m_idle_thread(min), m_cur_thread(min)
{
	//创建管理者线程
	m_manager = new thread(&ThreadPool::manager, this);

	//创建工作线程
	for (int i = 0; i < m_cur_thread; i++)
	{//使用emplace_back可以避免拷贝和移动，这个匿名对象是在移出m_workers后才会销毁
		
		thread t(&ThreadPool::worker, this);
		m_workers.insert(make_pair(t.get_id(), move(t)));
	}
}

void ThreadPool::add_task(function<void()> task)
{
	{
		//lock_guard对象可以帮我们智能管理互斥锁，对象析构时会自动解锁
		lock_guard<mutex> locker(m_queue_mx);
		m_tasks.emplace(task);
	}
	//唤醒消费者线程
	m_cond.notify_one();
}

void ThreadPool::manager()
{
	while (!m_shop.load())
	{
		//每隔三秒检测一次
		this_thread::sleep_for(chrono::seconds(3));

		int idle = m_idle_thread.load();
		int cur = m_cur_thread.load();

		//判断线程是否过多（根据实际情况来制定规则）
		if (idle > cur / 2 && cur > m_min_thread)
		{
			//每次销毁两个线程
			m_exit_thread.store(2);
			m_cond.notify_all();

			//退出的线程需要从m_workers对象中删除线程资源
			lock_guard<mutex> locker(m_ids_mx);
			for (const auto& id : m_ids)
			{
				auto it = m_workers.find(id);
				if (it != m_workers.end())
				{
					//调用join方法等待子线程处理完成
					cout << "=========线程 " << (*it).first << " 被销毁了..." << endl;
					(*it).second.join();
					m_workers.erase(it);
				}
			}
			m_ids.clear();
		}
		//判断线程是否过少（根据实际情况来制定规则）
		else if (idle == 0 && cur < m_max_thread)
		{
			thread t(&ThreadPool::worker, this);
			cout << "+++++++++++++++ 添加了一个线程, id: " << t.get_id() << endl;
			m_workers.insert(make_pair(t.get_id(), move(t)));
			m_cur_thread++;
			m_idle_thread++;
		}
	}
}


void ThreadPool::worker()
{
	while (!m_shop.load())
	{
		function<void()> task = nullptr;

		{	//添加一个作用域，作用是使unique_lock自动销毁解锁
			unique_lock<mutex> locker(m_queue_mx);
			//这里需要使用while不能使用if	防止多线程竞争问题需要回到前面判断一下是否还有任务
			while (!m_shop && m_tasks.empty())
			{
				//wait需要unique_lock互斥锁进行管理（调用wait方法会该互斥锁会自动解锁）
				m_cond.wait(locker);
				//判断是否需要销毁
				if (m_exit_thread.load() > 0)
				{
					m_cur_thread--;
					m_idle_thread--;
					m_exit_thread--;
					cout << "-------线程任务结束,ID: " << this_thread::get_id() << endl;
					lock_guard<mutex> locker(m_ids_mx);
					m_ids.emplace_back(this_thread::get_id());
					return;
				}
			}
			if (!m_tasks.empty())
			{
				cout << "取出了一个任务.." << endl;
				task = move(m_tasks.front());	//使用move 防止数据拷贝
				m_tasks.pop();
			}
		}

		if (task)
		{
			m_idle_thread--;
			task();		//处理任务
			m_idle_thread++;
		}
	}
}

ThreadPool::~ThreadPool()
{
	//关闭线程池
	m_shop = true;
	m_cond.notify_all();
	for (auto& it : m_workers)
	{
		thread& t = it.second;
		if (t.joinable())
		{
			cout << "******* 线程 " << t.get_id() << "将要退出.." << endl;
			t.join();
		}
	}

	if (m_manager->joinable())
	{
		m_manager->join();
	}
	delete m_manager;
}

#if 0			//同步
void calc(int x, int y)
{
	int z = x + y;
	cout << "z = " << z << endl;
	this_thread::sleep_for(chrono::seconds(2));
}

int main()
{
	ThreadPool pool(4);

	for (int i = 0; i < 10; i++)
	{
		//绑定参数
		auto obj = bind(calc, i, i * 2);
		res.emplace_back(pool.add_task(obj);
	}

	//阻塞主线程 等待子线程执行结束
	getchar();
	return 0;
}
#else		//异步
int calc(int x, int y)
{
	int z = x + y;
	this_thread::sleep_for(chrono::seconds(2));
	return z;
}

int main()
{
	ThreadPool pool(4);

	vector<future<int>> res;
	for (int i = 0; i < 10; i++)
	{
		res.emplace_back(pool.add_task(calc, i, i * 2));
	}

	for (auto&& item : res)
	{
		//item.get() 是阻塞函数，只有有数据写入才会解除阻塞拿到数据
		cout << "线程函数的返回值：" << item.get() << endl;
	}

	//任务处理完成无需阻塞
	return 0;
}
#endif
